import json
import os
import time
# import ctypes
from django.http import JsonResponse
from django.shortcuts import render, redirect

from camera_offset_django.settings import BASE_DIR
from main_function.models import CameraOffsetRecord, CameraInfo

from static.offset_py_files.camera_capture_queue import Camera
from static.offset_py_files.camera_offset_detect2 import offsetDetect
from static.offset_py_files.utils import parse_yaml, change_db
from datetime import datetime
from django.template import Template, Context

import numpy as np
############################
import logging

my_normal_logger = logging.getLogger('django')

############################
"""
因莫名原因 在启用mysql事务后间隔25秒以上的数据库操作会报错：
CR.CR_SERVER_LOST, "Lost connection to MySQL server during query"
pymysql.err.OperationalError: (2013, 'Lost connection to MySQL server during query')
数据库信息： wait_timeout:30 (怀疑是因为等待时间太短导致mysql服务将此次链接中断，当再次用本次链接取查询时报错)
解决方案如下： 原理未知， 表面理解意思为操作完成后关闭本次链接 下次操作数据库时另起新的链接
"""
from django.db import connection


def close_connection():
    if not connection.in_atomic_block:
        connection.close()


#############################

save_dir = BASE_DIR + '/static/img_data'

MIN_MATCH_COUNT = 10
BEST_DISTANCE = 7
GOOD_DISTANCE = 30
date_position_y = 90
acc = 5
interval = 5
detect_args = {'normal': {'result_len': 40, 'thres': 0.9},
               'sensitive': {'result_len': 25, 'thres': 0.8}}

###############################
offset_camera_data = []
die_camera_data = []
all_camera = {}
current_camera_open_status = {}  # 记录初始化时摄像头的开始状态 当状态改变时修改数据库（该操作避免每时每刻都要写入数据库）

##############################
config_path = BASE_DIR + '/static/offset_py_files/camera_info_1023_local.yaml'
camera_objects = []
sensitive_camera_objects = []  # 敏感摄像头的偏移对象
camera_group = parse_yaml(config_path)
cnt = 0

for k, v in camera_group.items():
    ip = v['ip']
    # name = v['name']
    # passwd = v['passwd']
    # camera_url = 'rtsp://%s:%s@%s/' % (name, passwd, ip)
    camera_url = cnt
    ip_str = ip.replace('.', '_')
    cnt += 1

    cap_ = Camera(camera_url, acc=acc)
    cap_.run()
    is_sensitive = CameraInfo.objects.filter(ip=ip_str).first().ip_is_sensitive
    close_connection()
    print('is_sensitive', is_sensitive)
    if is_sensitive == 0:
        offset_detect = offsetDetect(ip,
                                     cap_,
                                     save_dir,
                                     detect_args['normal']['result_len'],
                                     detect_args['normal']['thres'],
                                     MIN_MATCH_COUNT,
                                     BEST_DISTANCE,
                                     GOOD_DISTANCE,
                                     date_position_y)
        camera_objects.append(offset_detect)
    elif is_sensitive == 1:
        offset_detect = offsetDetect(ip,
                                     cap_,
                                     save_dir,
                                     detect_args['sensitive']['result_len'],
                                     detect_args['sensitive']['thres'],
                                     MIN_MATCH_COUNT,
                                     BEST_DISTANCE,
                                     GOOD_DISTANCE,
                                     date_position_y)
        sensitive_camera_objects.append(offset_detect)
    all_camera[str(ip_str)] = offset_detect
    current_camera_open_status[str(ip_str)] = cap_.cam.isOpened()


def show(request):
    my_normal_logger.info('####################  渲染主界面  #######################')
    return render(request, 'index.html')


def show_data(request):
    all_camera_ip = []
    if request.POST['region'] != 'ALL':
        region = request.POST['region'][0]  # 'E 区'[0] 只取E字母
        for c, i in enumerate(CameraInfo.objects.filter(region=region)):
            all_camera_ip.append([c, i.ip, i.detail_region])
        my_normal_logger.info('####################  选择区域后重新渲染主界面  #######################')
        return JsonResponse({'all_camera_ip': all_camera_ip})
    else:
        for c, i in enumerate(CameraInfo.objects.all()):
            all_camera_ip.append([c, i.ip, i.detail_region])
        print(all_camera_ip)
        return JsonResponse({'all_camera_ip': all_camera_ip})


def main_loop(request):
    global current_camera_open_status
    my_normal_logger.info('Run main loop')

    while True:
        for camera_obj in camera_objects:
            camera_ip = camera_obj.camera_ip
            my_normal_logger.info('Current Camera IP:' + str(camera_ip))
            ip_str_ = camera_obj.camera_ip.replace('.', '_')
            cap = camera_obj.cap
            cap.is_sleep = False
            # 更新摄像头状态 如果isOpened为False时更新到列表中并于前端显示
            print('cap.cam.isOpened()', cap.cam.isOpened(), camera_ip)
            # 读取初始化时摄像头的开始状态 当状态改变时修改数据库（该操作避免每时每刻都要写入数据库）
            if current_camera_open_status[str(ip_str_)] != cap.cam.isOpened():
                change_db(table_name='CameraInfo', operation_type='update', ip=ip_str_,
                          ip_is_work=1 if cap.cam.isOpened() else 0)
                close_connection()
                current_camera_open_status[str(ip_str_)] = cap.cam.isOpened()

            if not cap.cam.isOpened():
                # 如果该摄像头工作异常并不存在于异常列表中则append
                if ip_str_ not in die_camera_data:
                    die_camera_data.append(ip_str_)
            else:
                # 如果该摄像头工作正并存在于异常列表中则remove
                if ip_str_ in die_camera_data:
                    die_camera_data.remove(ip_str_)

            start = time.time()
            count = 0
            while time.time() - start <= interval:
                if not cap.frame_queue.empty():
                    data = cap.frame_queue.get()
                    frame = data["image"]
                    count += 1
                    is_offset_status = camera_obj.detect(frame)
                    cap.frame_queue.task_done()
                    if is_offset_status[0]:
                        time_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                        change_db(table_name='CameraOffsetRecord', operation_type='creat', ip=ip_str_,
                                  offset_pic_path=is_offset_status[1],
                                  offset_date=time_str)
                        region = CameraInfo.objects.filter(ip=ip_str_).first().region
                        close_connection()
                        offset_camera_data.append(
                            {'ip': ip_str_, 'offset_image_path': is_offset_status[1], 'offset_time': time_str,
                             'region': region})

            cap.is_sleep = True
            my_normal_logger.info('Camera IP:' + str(camera_ip) + ' Sleep')


def camera_offset(request):
    global offset_camera_data, die_camera_data
    # temp = offset_camera_data
    # offset_camera_data = []
    my_normal_logger.info('Succeed request from wed')
    return JsonResponse({'offset_camera_data': offset_camera_data, 'die_camera_data': die_camera_data})


def reset_camera(request):
    global offset_camera_data
    ip_ = request.POST['ip']
    my_normal_logger.info('Reset Camera IP:' + str(ip_))
    for i in offset_camera_data:
        if i['ip'] == ip_:
            offset_camera_data.remove(i)
    time_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    change_db(table_name='CameraOffsetRecord', operation_type='update', ip=ip_, reset_date=time_str)
    close_connection()
    current_frame = all_camera[ip_].cap.frame_queue.get()
    all_camera[ip_].offset_init(current_frame["image"])
    return JsonResponse({'status': 200})


def offset_record(request):
    ip_str_ = request.POST['ip']
    offset_camera_record = CameraOffsetRecord.objects.filter(ip=ip_str_).values()
    close_connection()
    my_normal_logger.info('Succeed request from wed for offset_record')

    return JsonResponse({'offset_camera_record': list(offset_camera_record)})


def main_loop_sensitive(request):
    print('################## run sensitive main loop ##########################################################')
    sensitive_camera_caps_dicts = {obj.camera_ip: obj for obj in sensitive_camera_objects}

    while True:  # 连续获取所有敏感摄像头interval的时间长图片
        cnt = 0
        lis_pics = []

        while cnt < detect_args['sensitive']['result_len']:  # 25表示25张图片即5s视频流
            for obj in sensitive_camera_caps_dicts.values():  # py3.6之后默认就是有序的
                ip_str_ = obj.camera_ip.replace('.', '_')
                cap = obj.cap
                cap.is_sleep = False
                # 更新摄像头状态 如果isOpened为False时更新到列表中并于前端显示
                # print('cap.cam.isOpened()', cap.cam.isOpened(), ip_str_)
                # 读取初始化时摄像头的开始状态 当状态改变时修改数据库（该操作避免每时每刻都要写入数据库）
                if current_camera_open_status[str(ip_str_)] != cap.cam.isOpened():
                    change_db(table_name='CameraInfo', operation_type='update', ip=ip_str_,
                              ip_is_work=1 if cap.cam.isOpened() else 0)
                    # close_connection()
                    current_camera_open_status[str(ip_str_)] = cap.cam.isOpened()
                if not cap.cam.isOpened():
                    # 如果该摄像头工作异常并不存在于异常列表中则append
                    if ip_str_ not in die_camera_data:
                        die_camera_data.append(ip_str_)
                else:
                    # 如果该摄像头工作正并存在于异常列表中则remove
                    if ip_str_ in die_camera_data:
                        die_camera_data.remove(ip_str_)

                if not obj.cap.frame_queue.empty():
                    data = obj.cap.frame_queue.get()
                    frame = data["image"]
                    if obj.pre_frame is None:  # 先分别对敏感摄像头初始化 获取self.pre_frame 帧
                        obj.offset_init(frame)

                    obj.cap.frame_queue.task_done()
                    lis_pics.append(frame)

                    cnt += 1
                else:
                    lis_pics.append(np.array([0]))
                    cnt += 1

        else:
            for i, obj in enumerate(sensitive_camera_caps_dicts.values()):
                for frame in np.array(lis_pics)[i::len(sensitive_camera_caps_dicts)]:
                    if frame.tolist() != [0]:
                        is_offset_status = obj.detect(frame)
                    else:
                        is_offset_status = [False]
                    # print(i, 'is_offset_status', is_offset_status)
                    if is_offset_status[0]:
                        ip_str_ = obj.camera_ip.replace('.', '_')
                        time_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                        change_db(table_name='CameraOffsetRecord', operation_type='creat', ip=ip_str_,
                                  offset_pic_path=is_offset_status[1],
                                  offset_date=time_str)
                        region = CameraInfo.objects.filter(ip=ip_str_).first().region
                        close_connection()
                        offset_camera_data.append(
                            {'ip': ip_str_, 'offset_image_path': is_offset_status[1], 'offset_time': time_str,'region': region})
